using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
using TPXSDK.NET.GIS;
using TPXSDK.NET.Link;
using TPXSDK.NET.Mission;
using TPXSDK.NET.Share;
using TPXSDK.NET.UObject;

namespace TPXSDK.NET.UAV;

/// <summary>
/// 飞机管理类
/// </summary>
public class UAVAdmin
{
    #region 成员变量
    private readonly List<UAVItem> _uavList = [];

    /// <summary>
    /// 当前被选中的UAV对象，任何情况下仅仅只能选择一个
    /// </summary>
    public UAVItem? CurrUAV { get; private set; }

    /// <summary>
    /// 前一个被选中的UAV对象
    /// </summary>
    public UAVItem? PrevUAV { get; private set; }

    /// <summary>
    /// 获取UAV集合只读列表
    /// </summary>
    public ReadOnlyCollection<UAVItem> Items => _uavList.AsReadOnly();

    /// <summary>
    /// 保存当前操作错误信息
    /// </summary>
    public string ErrorMsg { get; set; } = string.Empty;
    #endregion

    /// <summary>
    /// 构造函数
    /// </summary>
    public UAVAdmin()
    {

    }

    /// <summary>
    /// 关闭程序时进行清理工作，防止发生访问已经释放资源的异常
    /// </summary>
    public void DeInit()
    {
        // 关闭所有DataLink
        foreach (var uav in _uavList)
        {
            uav.IsConnected = false;
            uav.Link?.Close();
            uav.Link = null;
        }
        CurrUAV = null;
        PrevUAV = null;
        _uavList.Clear();
    }

    /// <summary>
    /// 检查当前UAV是否可进行通讯交互
    /// </summary>
    public bool IsReady
    {
        get
        {
            if (CurrUAV == null) return false;
            if (CurrUAV.Link == null) return false;
            if (!CurrUAV.Link.IsOpened) return false;
            return true;
        }
    }

    /// <summary>
    /// 根据UID信息查找是否存在
    /// </summary>
    private UAVItem? FindItem(uint uid)
    {
        foreach (var item in _uavList)
        {
            if (item.UID == uid) return item;
        }
        return null;
    }

    /// <summary>
    /// 根据通讯接口查询UAV设备列表
    /// </summary>
    public List<UAVItem> FindItem(CommAdapter ca)
    {
        var result = new List<UAVItem>();

        foreach (var item in _uavList)
        {
            if (item.Link?.Comm == ca)
            {
                result.Add(item);
            }
        }
        return result;
    }

    private static AbsPos GenAbsPos(object? lng, object? lat, object? alt)
    {
        if (null == lng || null == lat || null == alt)
        {
            return AbsPos.Zero;
        }

        return new AbsPos
        {
            Lng = Convert.ToDouble(lng) / 1e7,
            Lat = Convert.ToDouble(lat) / 1e7,
            Alt = Convert.ToDouble(alt)
        };
    }

    private static UAVItem CreateItem(UDevType type, uint uid, byte devid)
    {
        var uav = new UAVItem($"UAV-{devid}", type)
        {
            UID = uid,
            DevID = devid,
            Link = new TPLink("LNK") { DevAddr = devid }
        };

        var rootPath = Path.Combine(AppContext.BaseDirectory, uav.Name);
        if (!Directory.Exists(rootPath))
        {
            Directory.CreateDirectory(rootPath);
        }

        // 创建默认文件夹
        var prePaths = new[] { "TLM", "CFG", "LOG", "MIS" };

        foreach (var p in prePaths)
        {
            var path = Path.Combine(rootPath, p);
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }

        uav.TlmPath = Path.Combine(rootPath, prePaths[0]);
        uav.SettingPath = Path.Combine(rootPath, prePaths[1]);
        uav.LogPath = Path.Combine(rootPath, prePaths[2]);
        uav.MissionPath = Path.Combine(rootPath, prePaths[3]);

        return uav;
    }

    /// <summary>
    /// 更新已有设备列表，如果不存在创建之
    /// </summary>
    public UAVItem Update(UDevType type, uint uid, byte devid, CommAdapter ca)
    {
        var uav = FindItem(uid);

        bool isNewOne = false;
        if (null == uav)
        {
            uav = CreateItem(type, uid, devid);
            _uavList.Add(uav);// 加入对象列表
            isNewOne = true;
        }
        uav.DevID = devid;

        // 自动打开通信接口
        uav.Link?.Open(ca);

        if (isNewOne)
        {
            AddItemEvent?.Invoke(uav);
        }

        // 默认选择首个UAV
        if (null == CurrUAV)
        {
            SelectItem(uav);
        }

        return uav;
    }

    #region UAV选择
    /// <summary>
    /// 选中指定UAVItem对象
    /// </summary>
    public void SelectItem(UAVItem uav)
    {
        // 防止重复选中
        if (CurrUAV == uav)
        {
            return;
        }
        PrevUAV = CurrUAV;
        CurrUAV = uav;
        Trace.WriteLine($"当前UAV: {CurrUAV.DevID}");
        SelectItemEvent?.Invoke(PrevUAV, CurrUAV);
    }

    #endregion

    #region UAV查询
    /// <summary>
    /// 根据名称查找UAVItem
    /// </summary>
    public UAVItem? Find(string name)
    {
        if (string.IsNullOrEmpty(name) ||
            string.IsNullOrWhiteSpace(name))
        {
            return null;
        }
        return _uavList.FirstOrDefault(item => name == item.Name);
    }

    /// <summary>
    /// 根据UID 查找UAV
    /// </summary>
    public UAVItem? FindByUID(uint uid)
    {
        for (var i = 0; i < _uavList.Count; i++)
        {
            if (_uavList[i].UID == uid)
            {
                return _uavList[i];
            }
        }
        return null;
    }

    #endregion

    #region 工具函数
    /// <summary>
    /// 执行Home点循环读取[异步]
    /// </summary>
    public async Task<bool> ReadHomeLocation(UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        var homeLoc = await lnk.DoCmdGetUObj(uav.Admin["HomeLoc"]);
        if (null != homeLoc)
        {
            var loc = GenAbsPos(homeLoc["Lng"], homeLoc["Lat"], homeLoc["Alt"]);
            if (loc.IsValid)
            {
                uav.HomeLoc = loc;
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// 读取备降点集合
    /// </summary>
    public async Task<bool> ReadALTA(IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        ErrorMsg = string.Empty;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        var uobjs = uav.Admin.GetUObjs("AlterAPRT");
        var alta = new List<ALTAItem>();
        if (uobjs.Count > 0)
        {
            for (int i = 0; i < uobjs.Count; i++)
            {
                mon?.StepInfo($"{Tr.Get("Read")} ALTA[{i}]...", 100 * (i + 1) / uobjs.Count);
                var res = await lnk.DoCmdGetUObj(uobjs[i]);
                if(res == null) return false;
                var a = new ALTAItem();
                a.Pos.Lng = Convert.ToInt32(res["Lng"]) / 1e7;
                a.Pos.Lat = Convert.ToInt32(res["Lat"]) / 1e7;
                a.Pos.Alt = Convert.ToSingle(res["Alt"]);
                alta.Add(a);
            }
        }

        uav.Property<ALTAItem[]>().Value = [.. alta];
        return true;
    }

    /// <summary>
    /// 读取电子围栏
    /// </summary>
    public async Task<bool> ReadFence(IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        var cFenceArray = new FenceCircle[4];
        for (int i = 0; i < cFenceArray.Length; i++)
        {
            mon?.StepInfo($"{Tr.Get("Read")} CircleFence[{i}]...", 30 + 5 * i);
            var res = await lnk.DoCmdGetUObj(uav.Admin[$"Circlefence[{i}]"]);
            if (null == res) { return false; }
            cFenceArray[i] = new FenceCircle
            {
                Center = GenAbsPos(res["Lng"], res["Lat"], res["Alt"]),
                Radius = Convert.ToUInt16(res["Radius"]),
                Inverted = Convert.ToBoolean(res["Inverted"]),
                Enabled = Convert.ToBoolean(res["Enabled"])
            };
        }

        var pFenceArray = new FencePoly[2];
        for (int i = 0; i < pFenceArray.Length; i++)
        {
            mon?.StepInfo($"{Tr.Get("Read")} FencePoly[{i}]...", 60 + 5 * i);
            var res = await lnk.DoCmdGetUObj(uav.Admin[$"Polyfence[{i}]"]);
            if (null == res) { return false; }

            pFenceArray[i] = new FencePoly
            {
                PointCnt = Convert.ToUInt16(res["PointCnt"]),
                Inverted = Convert.ToBoolean(res["Inverted"]),
                Vertex = [
                    GenAbsPos(res["P1Lng"], res["P1Lat"], res["Alt"]),
                    GenAbsPos(res["P2Lng"], res["P2Lat"], res["Alt"]),
                    GenAbsPos(res["P3Lng"], res["P3Lat"], res["Alt"]),
                    GenAbsPos(res["P4Lng"], res["P4Lat"], res["Alt"]),
                    GenAbsPos(res["P5Lng"], res["P5Lat"], res["Alt"]),
                    GenAbsPos(res["P6Lng"], res["P6Lat"], res["Alt"])
                ]
            };
        }

        // 更新围栏数据属性
        uav.Property<FenceCircle[]>().Value = cFenceArray;
        uav.Property<FencePoly[]>().Value = pFenceArray;

        // 强制刷新电子围栏
        uav.Property<FenceCircle[]>().NotifyChanged();
        uav.Property<FencePoly[]>().NotifyChanged();

        return true;
    }

    /// <summary>
    /// 执行联机过程[异步]
    /// </summary>
    public async Task<bool> Connect(IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav)
        {
            return false;
        }

        if (uav.Admin == null)
        {
            mon?.StepInfo($"{Tr.Get("Read")} {Tr.Get("UObjMeta")} ...", 50);

            var res = await ReadUObjMeta(mon, uav);
            if (false == res)
            {
                ErrorMsg = $"{Tr.Get("Read")} {Tr.Get("UObjMeta")} {Tr.Get("Error")}";
                return false;
            }
        }

        if (uav.Admin == null)
        {
            return false;
        }

        lnk.RspTimeOut = 2000;

        // 启动联机过程
        // Step0 Read UObjFirmware
        mon?.StepInfo($"{Tr.Get("Read")} Firmware...", 10);
        var fm = await lnk.DoCmdGetUObj(uav.Admin["Firmware"]);
        if (null != fm)
        {
            // 确保设备类型一致
            var devType = Convert.ToInt32(fm["Type"]);
            if (!Enum.IsDefined(typeof(UDevType), devType))
            {
                ErrorMsg = $"Invalid DevType";
                return false;
            }
        }
        else
        {
            return false;
        }

        if (uav.UavType == UDevType.MRBOX ||
            uav.UavType == UDevType.RADIO)
        {
            uav.IsConnected = true;
            mon?.Complete($"{uav.UavType} {Tr.Get("Connect")}{Tr.Get("Success")}");
            return true;
        }

        if (uav.UavType == UDevType.UNKNOWN)
        {
            ErrorMsg = $"{Tr.Get("Unsupport")}: {uav.UavType}";
            return false;
        }

        // Step1 读取 GuideStatus
        mon?.StepInfo($"{Tr.Get("Read")} GuideStatus...", 20);
        var guideStatus = await lnk.DoCmdGetUObj(uav.Admin["GuideStatus"]);
        if (null != guideStatus)
        {
            uav.GuideLoc = GenAbsPos(
                guideStatus["Lng"],
                guideStatus["Lat"],
                guideStatus["Alt"]);
        }
        else
        {
            ErrorMsg = $"{Tr.Get("Read")} GuideStatus {Tr.Get("Fail")}";
            return false;
        }

        // Step2 读取电子围栏
        if (!await ReadFence(mon, uav))
        {
            ErrorMsg = $"{Tr.Get("Read")}{Tr.Get("Fence")}{Tr.Get("Fail")}";
            return false;
        }

        // Step3 读取备降点集合
        if (!await ReadALTA(mon, uav))
        {
            mon?.StepInfo($"{Tr.Get("Read")}{Tr.Get("ALTA")}{Tr.Get("Fail")}", 0);
        }

        mon?.Complete($"{Tr.Get("Connect")}{Tr.Get("Success")}");
        uav.IsConnected = true;
        return true;
    }

    /// <summary>
    /// 执行任务读取过程[异步-从飞控读取]
    /// </summary>
    public async Task<bool> ReadMission(IMonNotify? mon, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        // 启动任务读取过程
        var ret = await lnk.DoCmdMissionQueryFlyAdmin(0);
        var count = ret[0];
        if (count < 0)
        {
            ErrorMsg = $"{Tr.Get("Read")}{Tr.Get("Mission")}{Tr.Get("Error")}";
            return false;
        }

        uav.FlyCmdList = [];

        for (ushort i = 0; i < count; i++)
        {
            mon?.StepInfo($"{Tr.Get("Read")} FlyItem-{i}", 100 * i / count);
            var cmdItem = await lnk.DoCmdMissionQueryFlyItem(0, i);
            if (null == cmdItem)
            {
                ErrorMsg = $"{Tr.Get("Read")} FlyItem-{i} {Tr.Get("Error")}";
                return false;
            }
            uav.FlyCmdList.Add(cmdItem);
        }

        uav.Mission = string.Empty;
        var cmp = new FlyCompiler();
        uav.Mission = cmp.Decompile(uav.FlyCmdList);
        mon?.Complete($"{Tr.Get("Read")}{Tr.Get("Mission")}{Tr.Get("Success")}");
        return true;
    }

    /// <summary>
    /// 执行任务装载过程[异步-写入到飞控]
    /// </summary>
    public async Task<bool> WriteMission(string fn, byte misId, IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        var cmp = new FlyCompiler();

        // Load file and gen fly cmd list
        if (!cmp.Compile(fn) || cmp.CmdList.Count == 0)
        {
            mon?.Error($"{Tr.Get("Invalid Mission")}");
            return false;
        }
        ushort crc = 0;

        // 上传FlyItem列表
        for (ushort i = 0; i < cmp.CmdList.Count; i++)
        {
            var pct = 100 * i / cmp.CmdList.Count;
            mon?.StepInfo($"{Tr.Get("Write")} FlyItem-{i}...", pct);

            var rspCode = await lnk.DoCmdMissionEditFlyItem(misId, i, cmp.CmdList[i]);
            if (rspCode != RspCode.RSP_OK)
            {
                ErrorMsg = $"{Tr.Get("Write")} FlyItem-{i} {Tr.Get("Error")} : {rspCode}";
                return false;
            }
            var bytes = cmp.CmdList[i].GetBytes();
            crc += CRC16.Calc(bytes, 0, bytes.Length);
        }

        // 上传FlyAdmin
        var rspCode2 = await lnk.DoCmdMissionEditFlyAdmin(misId, (ushort)cmp.CmdList.Count, crc);
        if (rspCode2 != RspCode.RSP_OK)
        {
            ErrorMsg = $"{Tr.Get("Write")} FlyAdmin {Tr.Get("Error")}";
            return false;
        }

        // 成功后通知加载运行Mission
        rspCode2 = await lnk.DoCmdMissionEditUpdate(misId);
        if (rspCode2 != RspCode.RSP_OK)
        {
            ErrorMsg = ("Run Mission Error");
            return false;
        }

        // 更新本地Mission文本
        uav.FlyCmdList.Clear();
        uav.FlyCmdList.AddRange(cmp.CmdList);
        uav.Mission = cmp.Decompile(cmp.CmdList);

        mon?.Complete($"{Tr.Get("Write")}{Tr.Get("Mission")}{Tr.Get("Success")}");
        return true;
    }

    /// <summary>
    /// 读取当前UObjMeta信息
    /// </summary>
    public async Task<bool> ReadUObjMeta(IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav)
        {
            return false;
        }

        // 读取UObject签名
        var res = await lnk.DoCmdGetUObjMeta(UObjMetaSubCmd.SIG, null);
        if (res != RspCode.RSP_OK || lnk.RspData?.Length != 5)
        {
            ErrorMsg = $"{Tr.Get("Read")} {Tr.Get("UObjMeta")} SIG {Tr.Get("Error")}";
            return false;
        }

        var sig = DataUtils.GEN_UINT32(lnk.RspData[0], lnk.RspData[1], lnk.RspData[2], lnk.RspData[3]);
        var devType = (UDevType)Enum.ToObject(typeof(UDevType), lnk.RspData[4]);

        // 检测本地是否有缓存
        var admin = new UObjAdmin(sig, devType);
        if (admin.AllMeta.Count != 0)
        {
            if (null == uav.Admin || uav.Admin.Signature != sig)
            {
                uav.Admin = new UObjAdmin(sig, devType);
            }

            return true;
        }

        // 读取Class Meta
        res = await lnk.DoCmdGetUObjMeta(UObjMetaSubCmd.CLS, [0]);
        if (res != RspCode.RSP_OK)
        {
            ErrorMsg = $"{Tr.Get("Read")} {Tr.Get("UObjMeta")} Class {Tr.Get("Error")}";
            return false;
        }

        var index = 0;
        int totalCnt = lnk.RspData[index++];

        var meta = new UObjMeta
        {
            TypeId = lnk.RspData[index++],
            TypeSz = lnk.RspData[index++],
            InstCnt = DataUtils.GEN_WORD(lnk.RspData[index + 0], lnk.RspData[index + 1])
        };
        index += 2;
        meta.IsSetting = lnk.RspData[index++] != 0;
        meta.MemCnt = lnk.RspData[index++];
        meta.TypeName = Encoding.ASCII.GetString(lnk.RspData[index..]).TrimEnd('\0');
        admin.AllMeta.Add(meta);

        for (var i = 1; i < totalCnt; i++)
        {
            mon?.StepInfo($"{Tr.Get("Read")} ClassMeta {meta.TypeName}", i * 100 / totalCnt);
            res = await lnk.DoCmdGetUObjMeta(UObjMetaSubCmd.CLS, [(byte)i]);
            if (RspCode.RSP_OK != res) return false;

            index = 0;
            totalCnt = lnk.RspData[index++];
            meta = new UObjMeta
            {
                TypeId = lnk.RspData[index++],
                TypeSz = lnk.RspData[index++],
                InstCnt = DataUtils.GEN_WORD(lnk.RspData[index + 0], lnk.RspData[index + 1])
            };
            index += 2;
            meta.IsSetting = lnk.RspData[index++] != 0;
            meta.MemCnt = lnk.RspData[index++];
            meta.TypeName = Encoding.ASCII.GetString(lnk.RspData[index..]).TrimEnd('\0');
            admin.AllMeta.Add(meta);
        }

        // 读取Member Meta
        var metaIndex = 0;
        foreach (var item in admin.AllMeta)
        {
            mon?.StepInfo($"{Tr.Get("Read")} MemberMeta {item.TypeName}", metaIndex++ * 100 / totalCnt);

            // Member ID 从1开始，0代表整个UOBJ对象
            for (var i = 1; i <= item.MemCnt; i++)
            {
                res = await lnk.DoCmdGetUObjMeta(UObjMetaSubCmd.MEM, [item.TypeId, (byte)i]);
                if (RspCode.RSP_OK == res)
                {
                    // 检查回复数据有效性
                    if (item.TypeId != lnk.RspData[0] || i != lnk.RspData[1])
                    {
                        return false;
                    }
                    // ---------------------------------------------------
                    // 解析成员Meta数据格式：
                    // MemType[1Byte]+MemName[变长\0结尾]+MemUnit[变长\0结尾]
                    // ---------------------------------------------------
                    item.MemType[i - 1] = (MetaDataType)lnk.RspData[2];
                    bool findEos = false; // End of string
                    for (var j = 3; j < lnk.RspData.Length; j++)
                    {
                        // 查找成员名称结束符
                        if (lnk.RspData[j] == '\0')
                        {
                            // 截取成员名称
                            item.MemName[i - 1] = Encoding.ASCII.GetString(lnk.RspData[3..j]).TrimEnd('\0');
                            // 截取成员单位
                            if (j < (lnk.RspData.Length - 2))
                            {
                                var startIndex = j + 1;
                                var endIndex = lnk.RspData.Length - 1; //Remove '\0'
                                item.MemUnit[i - 1] = Encoding.ASCII.GetString(lnk.RspData[startIndex..endIndex]).TrimEnd('\0');
                            }
                            else
                            {
                                item.MemUnit[i - 1] = string.Empty;
                            }
                            findEos = true;
                            break;
                        }
                    }
                    if (!findEos)
                    {
                        item.MemName[i - 1] = Encoding.ASCII.GetString(lnk.RspData[3..]).TrimEnd('\0');
                    }
                }
                else
                {
                    return false;
                }
            }
        }

        if (!admin.SaveMeta())
        {
            ErrorMsg = $"{Tr.Get("Save")} {Tr.Get("UObjMeta")} {Tr.Get("Fail")}";
            return false;
        }

        // 更新创建UObjAdmin
        uav.Admin = new UObjAdmin(sig, devType);

        mon?.Complete($"{Tr.Get("Read")} {Tr.Get("UObjMeta")} {Tr.Get("Success")}");
        return true;
    }

    /// <summary>
    /// 读取指定UAV对象的参数列表，并保存到文件
    /// </summary>
    public async Task<bool> ReadSetting(string fn, IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        // 读取UObject签名
        var res = await lnk.DoCmdGetUObjMeta(UObjMetaSubCmd.SIG, null);
        if (res != RspCode.RSP_OK || lnk.RspData?.Length != 5)
        {
            ErrorMsg = $"{Tr.Get("Read")} {Tr.Get("UObjMeta")} SIG {Tr.Get("Error")}";
            return false;
        }

        var sig = DataUtils.GEN_UINT32(lnk.RspData[0], lnk.RspData[1], lnk.RspData[2], lnk.RspData[3]);
        var devType = (UDevType)Enum.ToObject(typeof(UDevType), lnk.RspData[4]);

        // 根据签名查找已经缓存的Meta模板
        var setting = new UObjAdmin(sig, devType, true);
        if (setting.AllMeta.Count == 0)
        {
            // 没有对应的Meta缓存, 重新读取并保存
            if (false == await ReadUObjMeta(mon, uav))
            {
                ErrorMsg = $"{Tr.Get("Read")} {Tr.Get("UObjMeta")} {Tr.Get("Error")}";
                return false;
            }
            setting = new UObjAdmin(sig, devType, true);
        }

        // (1) 循环读取
        var index = 0;
        foreach (var uobj in setting.ObjList)
        {
            var pct = 100 * (++index) / setting.ObjList.Count;
            mon?.StepInfo($"{Tr.Get("Read")} {uobj}...", pct);
            var rspObj = await lnk.DoCmdGetUObj(uobj);
            if (null == rspObj)
            {
                ErrorMsg = $"{Tr.Get("Read")} {uobj} {Tr.Get("Error")}";
                return false;
            }
            setting.UpdateUObj(rspObj);
        }

        // (2) 保存到文件
        setting.SaveSetting(fn);
        mon?.Complete($"{Tr.Get("Read")}{Tr.Get("Setting")}{Tr.Get("Success")}");

        return true;
    }

    /// <summary>
    /// 写入部分配置文件到飞控
    /// </summary>
    public async Task<bool> WriteSetting(Dictionary<uint, double> settings, IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        var index = 0;
        foreach (var setting in settings)
        {
            var pct = 100 * (++index) / settings.Keys.Count;
            var name = uav.Admin.FieldId2Str(setting.Key);
            mon?.StepInfo($"{Tr.Get("Write")} {name}...", pct);
            var rspCode = await lnk.DoCmdSetField(uav.Admin, setting.Key, setting.Value, true);
            if (rspCode != RspCode.RSP_OK)
            {
                ErrorMsg = $"{Tr.Get("Write")} {name} {Tr.Get("Error")}, {RspCodeHelper.ToStr(rspCode)}";
                return false;
            }
        }

        return true;
    }
    /// <summary>
    /// 写入完整配置文件到飞控
    /// </summary>
    public async Task<bool> WriteSetting(string fn, IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        // 判断当前飞机是否上锁状态
        if (!uav.IsLocked)
        {
            ErrorMsg = $"需要无人机上锁状态!";
            return false;
        }

        // (0) 读取UObject签名
        var res = await lnk.DoCmdGetUObjMeta(UObjMetaSubCmd.SIG, null);
        if (res != RspCode.RSP_OK || null == lnk.RspData || lnk.RspData.Length != 5)
        {
            ErrorMsg = $"{Tr.Get("Read")} {Tr.Get("UObjMeta")} SIG {Tr.Get("Error")}";
            return false;
        }

        var sig = DataUtils.GEN_UINT32(lnk.RspData[0], lnk.RspData[1], lnk.RspData[2], lnk.RspData[3]);
        var devType = (UDevType)Enum.ToObject(typeof(UDevType), lnk.RspData[4]);

        // (1) 加载参数文件
        // 设置待上传的Setting文件
        var setting = UObjAdmin.LoadSetting(fn);
        if (null == setting || setting.Signature != sig || setting.DevType != devType)
        {
            ErrorMsg = $"{Tr.Get("Invalid")} {Tr.Get("SettingFile")}";
            return false;
        }

        // (2) 循环写入
        var index = 0;
        foreach (var uobj in setting.ObjList)
        {
            if (!uobj.IsSetting) continue;

            var pct = 100 * (++index) / setting.ObjList.Count;
            mon?.StepInfo($"{Tr.Get("Write")} {uobj}...", pct);
            var rspCode = await lnk.DoCmdSetUObj(uobj);
            if (rspCode != RspCode.RSP_OK)
            {
                ErrorMsg = $"{Tr.Get("Write")} {uobj} {Tr.Get("Error")}, {RspCodeHelper.ToStr(rspCode)}";
                return false;
            }
        }

        // (3) 发送保存指令
        var rspCode2 = await lnk.DoCmdSaveSetting();
        if (rspCode2 != RspCode.RSP_OK)
        {
            ErrorMsg = $"{Tr.Get("Save")}{Tr.Get("Setting")}{Tr.Get("Error")}, {RspCodeHelper.ToStr(rspCode2)}";
            return false;
        }

        mon?.Complete($"{Tr.Get("Write")}{Tr.Get("SettingFile")}{Tr.Get("Success")}");
        return true;
    }

    /// <summary>
    /// 写入授权码
    /// </summary>
    public async Task<bool> Authorize(string hexStr, IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        var codes = DataUtils.HexStrToByte(hexStr);
        var rsp = await lnk.DoCmdDoAction(ActionSubCmd.AUTH, codes, true);
        if (rsp != RspCode.RSP_OK)
        {
            ErrorMsg = $"{Tr.Get("Write")} {Tr.Get("Fail")}";
            return false;
        }

        mon?.Complete($"{Tr.Get("Write")} {Tr.Get("Success")}");
        return true;
    }

    /// <summary>
    /// 读取多个UObject对象数据
    /// </summary>
    public async Task<bool> ReadUObjects(IList<UObjBase> uobjs, IMonNotify? mon = null, UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        // 循环读取
        var index = 0;
        foreach (var uobj in uobjs)
        {
            var pct = 100 * (++index) / uobjs.Count;
            mon?.StepInfo($"{Tr.Get("Read")} {uobj}...", pct);
            var rspObj = await lnk.DoCmdGetUObj(uobj);
            if (null == rspObj)
            {
                ErrorMsg = $"{Tr.Get("Read")} {uobj} {Tr.Get("Error")}";
                return false;
            }
            uav.Admin.UpdateUObj(rspObj);
        }

        mon?.Complete($"{Tr.Get("Read")}{Tr.Get("Success")}");

        return true;
    }

    /// <summary>
    /// 写入多个UObject对象数据
    /// </summary>
    public async Task<bool> WriteUObjects(IList<UObjBase> uobjs, IMonNotify? mon = null, UAVItem? uav = null, bool save2Flash = false)
    {
        uav ??= CurrUAV;
        var lnk = uav?.Link;
        if (!IsReady || null == lnk || null == uav || null == uav.Admin)
        {
            return false;
        }

        // 循环写入
        var index = 0;
        foreach (var uobj in uobjs)
        {
            var pct = 100 * (++index) / uobjs.Count;
            mon?.StepInfo($"{Tr.Get("Write")} {uobj}...", pct);
            var rspCode = await lnk.DoCmdSetUObj(uobj, true, save2Flash);
            if (rspCode != RspCode.RSP_OK)
            {
                ErrorMsg = $"{Tr.Get("Write")} {uobj} {Tr.Get("Error")}";
                return false;
            }
        }

        mon?.Complete($"{Tr.Get("Write")}{Tr.Get("Success")}");
        return true;
    }

    /// <summary>
    /// 执行断开联机(关闭TPLink相关逻辑)
    /// </summary>
    public void DisConnect(UAVItem? uav = null)
    {
        uav ??= CurrUAV;
        if (null == uav) return;

        // 重置相关属相
        uav.CmdStep = -1;
        uav.IsReady = false;
        uav.IsConnected = false;
        uav.ReCnntCount = 0;
        uav.HomeLoc = null;

        // 关闭链路以及检测
        uav.Link?.Close();
    }
    #endregion

    #region 事件定义
    public delegate void SelectItemHandler(UAVItem? prev, UAVItem? curr);
    public event SelectItemHandler? SelectItemEvent;

    public delegate void AddItemHandler(UAVItem uav);
    public event AddItemHandler? AddItemEvent;
    #endregion
}
